#include "block.h"

Block::Block(const RegisterFactory& regFactory,unsigned int blockSize) 
	: rf(regFactory){
	quantity = 0;
	this->blockSize = blockSize;
	this->fchained = false;
	this->fchain_begining = false;
	this->fchain_end = false;
}

Block::~Block(){	
	for(std::vector<char*>::iterator it = reg.begin();it!=reg.end();++it){	
		delete[] (*it);
	}
}

unsigned short Block::getFree(){
	//Calculo el espacio libre
	unsigned short size;
	unsigned short free_space = blockSize - Block::getHeaderSize();
	
	for(unsigned short i=0; i<quantity;i++){
		if(i == 0)
			size = blockSize - reg_offset[i];
		else
			size = reg_offset[i-1] - reg_offset[i];
		
		free_space -= size + Block::getDataControlSize();
	}
	
	return free_space;
}

unsigned short Block::getQuantity(){
		return quantity;
}

unsigned short Block::findMin(){
	std::vector <unsigned short> aux = reg_number;	
	std::sort(aux.begin(), aux.end());
	unsigned short min = 1;
	for(unsigned short i = 0;i<quantity;i++){
		if(aux[i]==min)
			min++;
	}
	return min;
}

unsigned short Block::addRegister(const Register &r, unsigned short reg_num){
	//Calculo espacio libre
	unsigned short free_space = getFree();
	
	//Si no es cero, lo inserto con ese numero	
	if(reg_num == 0){
		//Busco el nro minimo
		reg_num = findMin();
	}
	
	/* Aqui no tiene sentido realizar chequeo de espacio libre
       el mismo ya lo realiza el BlockFile  cuando busca un bloque adecuado 
	   para insertarlo */
	unsigned int new_offset;		
	
	quantity++;
	reg_number.push_back(reg_num);
	free_space -= r.getSize() + Block::getDataControlSize();
 		
	new_offset = free_space + Block::getHeaderSize()+Block::getDataControlSize()*quantity;
	reg_offset.push_back(new_offset);
		
	char *tmp = new char[r.getSize()];
	rf(r, tmp);
	reg.push_back(tmp);

	return reg_num;
}

Register *Block::getRegister(const unsigned short number){
	for(unsigned short i=0;i<quantity;i++){	
		if(reg_number[i]==number){
			return rf(reg[i]);
		}
	}
	return NULL;
}

void Block::removeRegister(const unsigned short number){
	std::vector <unsigned short>::iterator reg_number_it = reg_number.begin();
	std::vector <unsigned short>::iterator reg_offset_it = reg_offset.begin();
	std::vector <char*>::iterator reg_it = reg.begin();
	unsigned short size_acum=0, size=0;
	unsigned short count=0;
	bool deleted = false;

	while (reg_number_it != reg_number.end() && !deleted){
		if(*reg_number_it == number){
			if(reg_number_it == reg_number.begin())
				size = blockSize - *reg_offset_it;
			else
				size = blockSize - *reg_offset_it - size_acum;
			
			reg_number.erase(reg_number_it);
			reg_offset.erase(reg_offset_it);
			delete[] (*reg_it);
			reg.erase(reg_it);
			quantity--;
			deleted = true;
		}else{
			size_acum = blockSize - *reg_offset_it;
			++reg_number_it;
			++reg_offset_it;
			++reg_it;
			++count;
		}
	}

	/* Solo resta correr todos los offset que esten mas alla del borrado 
	   size para abajo */
	for(unsigned short c=count;c<quantity;++c){
		reg_offset[c] += size;
	}
}

char Block::getStatus()const{
	char ret = 0;
	if(fchained) ret += BLOCK_IS_CHAINED;
	if(fchain_begining) ret += BLOCK_IS_CHAIN_BEGINING;
	if(fchain_end) ret += BLOCK_IS_CHAIN_END;
	
	return ret;
}


void Block::setStatus(char status){
	fchained = ( status&(BLOCK_IS_CHAINED) );
	fchain_begining = ( status&(BLOCK_IS_CHAIN_BEGINING) );
	fchain_end = ( status&(BLOCK_IS_CHAIN_END) );
}
